package com.pokermind.operator.ai;

import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 德州扑克数学计算器
 * 提供胜率计算、概率分析、蒙特卡洛模拟等核心数学功能
 *
 * @author PokerMind Team
 */
@Component
public class PokerMathCalculator {

    // 标准52张牌的定义
    private static final String[] SUITS = {"h", "d", "c", "s"}; // hearts, diamonds, clubs, spades
    private static final String[] RANKS = {"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"};
    
    /**
     * 胜率计算结果
     */
    public static class EquityResult {
        private double winRate;           // 获胜概率 (0-1)
        private double tieRate;           // 平局概率 (0-1)
        private double equity;            // 总权益 = winRate + tieRate/2
        private Map<String, Double> handStrengthDistribution; // 牌力分布
        private int simulationCount;     // 模拟次数
        private long computationTimeMs;  // 计算时间
        
        // Getters and setters
        public double getWinRate() { return winRate; }
        public void setWinRate(double winRate) { this.winRate = winRate; }
        
        public double getTieRate() { return tieRate; }
        public void setTieRate(double tieRate) { this.tieRate = tieRate; }
        
        public double getEquity() { return equity; }
        public void setEquity(double equity) { this.equity = equity; }
        
        public Map<String, Double> getHandStrengthDistribution() { return handStrengthDistribution; }
        public void setHandStrengthDistribution(Map<String, Double> handStrengthDistribution) { this.handStrengthDistribution = handStrengthDistribution; }
        
        public int getSimulationCount() { return simulationCount; }
        public void setSimulationCount(int simulationCount) { this.simulationCount = simulationCount; }
        
        public long getComputationTimeMs() { return computationTimeMs; }
        public void setComputationTimeMs(long computationTimeMs) { this.computationTimeMs = computationTimeMs; }
    }
    
    /**
     * 概率分析结果
     */
    public static class OddsAnalysis {
        private double potOdds;          // 底池赔率
        private double impliedOdds;      // 隐含赔率
        private double reverseImpliedOdds; // 逆向隐含赔率
        private boolean correctToCall;   // 是否正确跟注
        private double expectedValue;    // 期望值
        private Map<String, Double> actionEV; // 各种行动的期望值
        
        // Getters and setters
        public double getPotOdds() { return potOdds; }
        public void setPotOdds(double potOdds) { this.potOdds = potOdds; }
        
        public double getImpliedOdds() { return impliedOdds; }
        public void setImpliedOdds(double impliedOdds) { this.impliedOdds = impliedOdds; }
        
        public double getReverseImpliedOdds() { return reverseImpliedOdds; }
        public void setReverseImpliedOdds(double reverseImpliedOdds) { this.reverseImpliedOdds = reverseImpliedOdds; }
        
        public boolean isCorrectToCall() { return correctToCall; }
        public void setCorrectToCall(boolean correctToCall) { this.correctToCall = correctToCall; }
        
        public double getExpectedValue() { return expectedValue; }
        public void setExpectedValue(double expectedValue) { this.expectedValue = expectedValue; }
        
        public Map<String, Double> getActionEV() { return actionEV; }
        public void setActionEV(Map<String, Double> actionEV) { this.actionEV = actionEV; }
    }
    
    /**
     * 蒙特卡洛模拟计算Hero胜率
     *
     * @param heroCards Hero的底牌 ["As", "Ks"]
     * @param boardCards 公共牌 ["Ah", "7s", "2c"] 可以是翻牌、转牌、河牌
     * @param opponentCount 对手数量
     * @param simulationCount 模拟次数，推荐10000-100000
     * @return 胜率计算结果
     */
    public EquityResult calculateEquity(List<String> heroCards, List<String> boardCards, 
                                       int opponentCount, int simulationCount) {
        long startTime = System.currentTimeMillis();
        
        // 验证输入
        if (heroCards == null || heroCards.size() != 2) {
            throw new IllegalArgumentException("Hero must have exactly 2 hole cards");
        }
        if (boardCards == null || boardCards.size() > 5) {
            throw new IllegalArgumentException("Board cannot have more than 5 cards");
        }
        if (opponentCount < 1 || opponentCount > 8) {
            throw new IllegalArgumentException("Opponent count must be between 1 and 8");
        }
        
        // 创建牌堆，移除已知的牌
        List<String> availableCards = createDeck();
        availableCards.removeAll(heroCards);
        availableCards.removeAll(boardCards);
        
        int wins = 0;
        int ties = 0;
        Map<String, Integer> handStrengthCount = new HashMap<>();
        
        // 蒙特卡洛模拟
        Random random = new Random();
        for (int i = 0; i < simulationCount; i++) {
            // 洗牌
            Collections.shuffle(availableCards, random);
            
            // 补全公共牌到5张
            List<String> simulatedBoard = new ArrayList<>(boardCards);
            int cardsNeeded = 5 - boardCards.size();
            for (int j = 0; j < cardsNeeded; j++) {
                simulatedBoard.add(availableCards.get(j));
            }
            
            // 为对手发底牌
            List<List<String>> opponentHands = new ArrayList<>();
            int cardIndex = cardsNeeded;
            for (int opponent = 0; opponent < opponentCount; opponent++) {
                List<String> opponentHand = Arrays.asList(
                    availableCards.get(cardIndex++),
                    availableCards.get(cardIndex++)
                );
                opponentHands.add(opponentHand);
            }
            
            // 评估各手牌强度
            HandRank heroRank = evaluateHand(heroCards, simulatedBoard);
            List<HandRank> opponentRanks = opponentHands.stream()
                .map(hand -> evaluateHand(hand, simulatedBoard))
                .collect(Collectors.toList());
            
            // 统计牌力分布
            handStrengthCount.merge(heroRank.getHandType(), 1, Integer::sum);
            
            // 比较结果
            boolean heroWins = true;
            boolean heroTies = false;
            
            for (HandRank opponentRank : opponentRanks) {
                int comparison = heroRank.compareTo(opponentRank);
                if (comparison < 0) {
                    heroWins = false;
                    break;
                } else if (comparison == 0) {
                    heroTies = true;
                }
            }
            
            if (heroWins && !heroTies) {
                wins++;
            } else if (heroTies) {
                ties++;
            }
        }
        
        // 计算结果
        EquityResult result = new EquityResult();
        result.setWinRate((double) wins / simulationCount);
        result.setTieRate((double) ties / simulationCount);
        result.setEquity(result.getWinRate() + result.getTieRate() / 2.0);
        result.setSimulationCount(simulationCount);
        result.setComputationTimeMs(System.currentTimeMillis() - startTime);
        
        // 转换牌力分布为概率
        Map<String, Double> handStrengthDistribution = new HashMap<>();
        handStrengthCount.forEach((handType, count) -> 
            handStrengthDistribution.put(handType, (double) count / simulationCount));
        result.setHandStrengthDistribution(handStrengthDistribution);
        
        return result;
    }
    
    /**
     * 计算概率分析
     *
     * @param currentPot 当前底池
     * @param betToCall 需要跟注的数量
     * @param heroStack Hero剩余筹码
     * @param equity Hero的胜率
     * @return 概率分析结果
     */
    public OddsAnalysis calculateOddsAnalysis(BigDecimal currentPot, BigDecimal betToCall, 
                                            BigDecimal heroStack, double equity) {
        OddsAnalysis analysis = new OddsAnalysis();
        
        // 计算底池赔率
        double potOdds = betToCall.doubleValue() / (currentPot.doubleValue() + betToCall.doubleValue());
        analysis.setPotOdds(potOdds);
        
        // 简化的隐含赔率计算
        double impliedOdds = potOdds * 0.8; // 保守估计
        analysis.setImpliedOdds(impliedOdds);
        
        // 逆向隐含赔率
        double reverseImpliedOdds = (1 - equity) * potOdds * 1.2;
        analysis.setReverseImpliedOdds(reverseImpliedOdds);
        
        // 是否正确跟注
        analysis.setCorrectToCall(equity > potOdds);
        
        // 期望值计算
        double callEV = equity * currentPot.add(betToCall).doubleValue() - betToCall.doubleValue();
        analysis.setExpectedValue(callEV);
        
        // 各种行动的期望值
        Map<String, Double> actionEV = new HashMap<>();
        actionEV.put("fold", 0.0);
        actionEV.put("call", callEV);
        actionEV.put("raise", callEV + betToCall.doubleValue() * 0.3); // 简化计算
        analysis.setActionEV(actionEV);
        
        return analysis;
    }
    
    /**
     * 创建标准52张牌的牌堆
     */
    private List<String> createDeck() {
        List<String> deck = new ArrayList<>();
        for (String rank : RANKS) {
            for (String suit : SUITS) {
                deck.add(rank + suit);
            }
        }
        return deck;
    }
    
    /**
     * 牌力评估结果
     */
    private static class HandRank implements Comparable<HandRank> {
        private int rank; // 牌力等级，数字越大越强
        private String handType; // 牌型名称
        private List<Integer> kickers; // 踢脚牌
        
        public HandRank(int rank, String handType, List<Integer> kickers) {
            this.rank = rank;
            this.handType = handType;
            this.kickers = kickers != null ? kickers : new ArrayList<>();
        }
        
        public String getHandType() { return handType; }
        
        @Override
        public int compareTo(HandRank other) {
            if (this.rank != other.rank) {
                return Integer.compare(this.rank, other.rank);
            }
            
            // 比较踢脚牌
            for (int i = 0; i < Math.min(this.kickers.size(), other.kickers.size()); i++) {
                int cmp = Integer.compare(this.kickers.get(i), other.kickers.get(i));
                if (cmp != 0) {
                    return cmp;
                }
            }
            
            return 0;
        }
    }
    
    /**
     * 评估手牌强度（简化版实现）
     * 这里是一个简化的实现，实际项目中应该使用更精确的牌力评估算法
     */
    private HandRank evaluateHand(List<String> holeCards, List<String> board) {
        List<String> allCards = new ArrayList<>();
        allCards.addAll(holeCards);
        allCards.addAll(board);
        
        // 简化实现：只检查基本牌型
        Map<String, Integer> rankCounts = new HashMap<>();
        Map<String, Integer> suitCounts = new HashMap<>();
        
        List<Integer> ranks = new ArrayList<>();
        
        for (String card : allCards) {
            String rank = card.substring(0, 1);
            String suit = card.substring(1);
            
            rankCounts.merge(rank, 1, Integer::sum);
            suitCounts.merge(suit, 1, Integer::sum);
            
            ranks.add(getRankValue(rank));
        }
        
        Collections.sort(ranks, Collections.reverseOrder());
        
        // 检查同花
        boolean isFlush = suitCounts.values().stream().anyMatch(count -> count >= 5);
        
        // 检查顺子
        boolean isStraight = checkStraight(ranks);
        
        // 检查对子、三条、四条等
        List<Integer> pairValues = rankCounts.entrySet().stream()
            .filter(e -> e.getValue() >= 2)
            .map(e -> getRankValue(e.getKey()))
            .sorted(Collections.reverseOrder())
            .collect(Collectors.toList());
        
        // 简化的牌力评估
        if (isFlush && isStraight) {
            if (ranks.contains(14)) { // A高
                return new HandRank(8, "Royal Flush", Arrays.asList(14));
            } else {
                return new HandRank(7, "Straight Flush", Arrays.asList(Collections.max(ranks)));
            }
        } else if (rankCounts.containsValue(4)) {
            return new HandRank(6, "Four of a Kind", pairValues);
        } else if (rankCounts.containsValue(3) && rankCounts.containsValue(2)) {
            return new HandRank(5, "Full House", pairValues);
        } else if (isFlush) {
            return new HandRank(4, "Flush", ranks.subList(0, Math.min(5, ranks.size())));
        } else if (isStraight) {
            return new HandRank(3, "Straight", Arrays.asList(Collections.max(ranks)));
        } else if (rankCounts.containsValue(3)) {
            return new HandRank(2, "Three of a Kind", pairValues);
        } else if (pairValues.size() >= 2) {
            return new HandRank(1, "Two Pair", pairValues);
        } else if (pairValues.size() == 1) {
            return new HandRank(0, "One Pair", pairValues);
        } else {
            return new HandRank(-1, "High Card", ranks.subList(0, Math.min(5, ranks.size())));
        }
    }
    
    private int getRankValue(String rank) {
        switch (rank) {
            case "A": return 14;
            case "K": return 13;
            case "Q": return 12;
            case "J": return 11;
            case "T": return 10;
            default: return Integer.parseInt(rank);
        }
    }
    
    private boolean checkStraight(List<Integer> ranks) {
        Set<Integer> uniqueRanks = new HashSet<>(ranks);
        List<Integer> sortedRanks = new ArrayList<>(uniqueRanks);
        Collections.sort(sortedRanks);
        
        // 检查普通顺子
        for (int i = 0; i <= sortedRanks.size() - 5; i++) {
            boolean isStraight = true;
            for (int j = 1; j < 5; j++) {
                if (sortedRanks.get(i + j) != sortedRanks.get(i + j - 1) + 1) {
                    isStraight = false;
                    break;
                }
            }
            if (isStraight) {
                return true;
            }
        }
        
        // 检查A-2-3-4-5顺子
        if (uniqueRanks.containsAll(Arrays.asList(14, 2, 3, 4, 5))) {
            return true;
        }
        
        return false;
    }
}
